<script setup lang="ts">
import type Typings from "@/typings";
import { computed, nextTick, onMounted, ref } from "vue";
import Validate from "@/validate";
import { $singleMsg } from "@/utils/element";
import service from "@/apis";

// 页面模式
const dialogMode = ref("view");

// 是否查看模式
const isView = computed(() => {
  return ["view"].includes(dialogMode.value);
});

// 是否为编辑模式
const isUpdate = computed(() => {
  return ["update"].includes(dialogMode.value);
});

// 表单内容
const formData = ref<Partial<Typings.Role.props>>({
  id: "",
  roleId: "",
  roleName: "",
  permissionKey: [],
  halfPermissionKey: [],
  permissionButtonKeys: []
});

// 控制器操作
const tree = ref();
const treeData = ref<Typings.Menu.props[]>([]);
const resolve = ref();
const reject = ref();
const visible = ref<boolean>(false);
const form = ref();
const controller = {
  // 获取树形控件数据
  async getMenuAllTree() {
    const { data } = await service.menuAllTreeApi();
    treeData.value = data;
  },

  // 打开弹窗
  open: async (
    data: Partial<Typings.Role.props> = {},
    mode: Typings.Common.modeType = "view"
  ) => {
    return new Promise((_resolve, _reject) => {
      visible.value = true;
      resolve.value = _resolve;
      reject.value = _reject;

      formData.value = { ...formData.value, ...data };
      dialogMode.value = mode;

      nextTick(() => {
        form.value.clearValidate();
      });
    });
  },

  // 关闭弹窗
  close: (shouldReject = true) => {
    visible.value = false;

    formData.value = {
      id: "",
      roleId: "",
      roleName: "",
      permissionKey: [],
      halfPermissionKey: [],
    };

    if (shouldReject) {
      reject.value(new Error("关闭弹窗"));
    }
  },

  // 检验表单
  validate: async () => {
    try {
      await form.value.validate();
      return Promise.resolve(true);
    } catch (err) {
      console.warn(err);
      const tip = "请完善表单";
      $singleMsg({ message: tip, type: "warning" });
      return Promise.reject(new Error(tip));
    }
  },

  // 确定
  confirm: async () => {
    await controller.validate();

    const apiService = {
      add: service.roleAddApi,
      update: service.roleUpdateApi,
    } as const; // 使用 as const 确保字面量类型

    await apiService[dialogMode.value as keyof typeof apiService]({
      ...formData.value,
    });

    $singleMsg({ message: "操作成功" });

    resolve.value(true);

    controller.close(false);
  },

  // 树形组件复选框变化时
  checkChange(data: Typings.Menu.props, checked: boolean) {
    // 变成未选中时，清空对应菜单的按钮选中值
    if (!checked) {
      const buttonKeys = data.buttonList?.map(i => i.key);
      formData.value.permissionButtonKeys = formData.value.permissionButtonKeys?.filter(i => !buttonKeys?.includes(i))
    }

    // 保存选中的菜单 key
    const checkKeys = tree.value.$refs.tree.getCheckedKeys();
    formData.value.permissionKey = checkKeys;

    // 保存半选的节点 key
    const halfCheckKeys = tree.value.$refs.tree.getHalfCheckedKeys();
    formData.value.halfPermissionKey = halfCheckKeys;
  },
};

onMounted(() => {
  controller.getMenuAllTree();
});

defineExpose({
  open: controller.open,
});
</script>

<template>
  <xt-dialog width="80%" v-model="visible" title="角色信息" :before-close="controller.close">
    <el-form ref="form" :model="formData" label-width="108px" :disabled="isView">
      <el-row :gutter="20">
        <el-col>
          <el-form-item label="ID" prop="roleId" :rules="Validate.Required()">
            <xt-input v-model="formData.roleId" :disabled="isUpdate" />
          </el-form-item>
        </el-col>

        <el-col>
          <el-form-item label="名称" prop="roleName" :rules="Validate.Required()">
            <xt-input v-model="formData.roleName" />
          </el-form-item>
        </el-col>

        <el-col>
          <el-form-item label="权限" prop="permissionKey" :rules="Validate.Required()">
            <xt-tree ref="tree" v-if="visible" class="w-full" default-expand-all
              :default-checked-keys="formData.permissionKey" show-checkbox node-key="key" :data="treeData"
              :props="{ children: 'children', label: 'title' }" @check-change="controller.checkChange">
              <template #default="{ data }">
                <div class="w-full flex flex-row justify-between items-center">
                  <span>{{ data.title }}</span>
                  <div @click.stop>
                    <el-checkbox-group v-model="formData.permissionButtonKeys">
                      <el-checkbox v-for="i in data.buttonList" :label="i.title" :value="i.key" />
                    </el-checkbox-group>
                  </div>
                </div>
              </template>
            </xt-tree>
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>

    <template #footer>
      <div>
        <xt-button @click="controller.confirm" v-if="!isView">确 定</xt-button>
        <xt-button type="default" @click="controller.close(true)">取 消</xt-button>
      </div>
    </template>
  </xt-dialog>
</template>

<style lang="scss" scoped></style>
